package com.karaku.karaku_collector.collector;

import android.os.Handler;
import android.os.Looper;
import android.view.SurfaceView;

import com.karaku.karaku_collector.LocalSetting;
import com.karaku.karaku_collector.agora.AgoraManager;
import com.karaku.karaku_collector.agora.CollectorRtcEventHandler;
import com.karaku.karaku_collector.collector.model.DynamicKey;
import com.karaku.karaku_collector.common.http.NetCallback;
import com.karaku.karaku_collector.common.http.NetError;
import com.karaku.karaku_collector.common.http.NetOperation;
import com.karaku.karaku_collector.util.LogUtil;

/**
 * Created by guoping on 2017/10/27.
 */

public class CollectorManager {

    public interface Listener extends AgoraManager.Listener {
        void onStateChanged(int state);
    }

    public static final int STATE_STOPPED = 0;
    public static final int STATE_STARTING = 1;
    public static final int STATE_STARTED = 2;

    private static final int RETRY_INTERVAL = 5 * 1000;
    private static final int TIMEOUT = 10 * 1000;

    private static  CollectorManager instance;
    public static CollectorManager getInstance() {
        if (instance == null) {
            instance = new CollectorManager();
        }
        return instance;
    }

    private boolean waitRetry = false;
    private int state = STATE_STOPPED;
    private boolean starting = false;
    private boolean stopped = true;
    private Handler retryHandler = new Handler(Looper.getMainLooper());
    private Handler countdownHandler = new Handler(Looper.getMainLooper());
    private DynamicKey dynamicKey;
    private Listener listener;
    private AgoraManager agoraManager;
    private NetOperation getDynamicKeyOperation;
    private NetOperation uploadRoomInfoOperation;

    private CollectorRtcEventHandler eventHandler = new CollectorRtcEventHandler() {
        @Override
        public void needRestart() {
            retry();
        }

        @Override
        public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
            super.onJoinChannelSuccess(channel, uid, elapsed);
            if (waitRetry) {
                return;
            }
            uploadRoomInfoOperation = CollectorApi.uploadRoomInfo(LocalSetting.getInstance().getRoomId(),
                    LocalSetting.getInstance().getDirection(),
                    uid, new NetCallback<Void>() {
                        @Override
                        public void failed(NetOperation operation, NetError error) {
                            if (error.isCanceled()) {
                                return;
                            }
                            CollectorStateManager.getInstance().setState(CollectorStateManager.STATE_RETRY_UPLOAD_ROOM_INFO, error.toString());
                            onFailed();
                        }

                        @Override
                        public void success(NetOperation operation, Void result) {
                            setState(STATE_STARTED);
                            CollectorStateManager.getInstance().setState(CollectorStateManager.STATE_NORMAL, null);
                            onSuccess();
                        }
                    });
        }
    };

    private CollectorManager() {
        CollectorRtcEventHandler.getGlobalHandler().addSubHandler(eventHandler);
    }

    public Listener getListener() {
        return listener;
    }

    public void setListener(Listener listener) {
        this.listener = listener;
    }

    public DynamicKey getDynamicKey() {
        return dynamicKey;
    }

    public SurfaceView getSurfaceView() {
        if (agoraManager != null) {
            return agoraManager.getSurfaceView();
        }
        return null;
    }

    public int getState() {
        return state;
    }

    public boolean isStopped() {
        return state == STATE_STOPPED;
    }

    public void start() {
        if (starting) {
            return;
        }
        starting = true;
        setState(STATE_STARTING);
        stopped = false;
        startCollector();
        LocalSetting.getInstance().setStarted(true);
    }

    public void stop() {
        stopped = true;
        LocalSetting.getInstance().setStarted(false);
        setState(STATE_STOPPED);
        CollectorStateManager.getInstance().setState(CollectorStateManager.STATE_STOPPED, null);
        stopCollector();
    }

    public void setScale(float scale) {
        if (agoraManager != null) {
            agoraManager.setScale(scale);
        }
    }

    public void setWhiteBalance(float[] whiteBalance) {
        if (agoraManager != null) {
            agoraManager.setWhiteBalance(whiteBalance);
        }
    }

    private void stopCollector() {
        if (agoraManager != null) {
            agoraManager.leaveChannel();
            agoraManager = null;
        }
        countdownHandler.removeCallbacksAndMessages(null);
        retryHandler.removeCallbacksAndMessages(null);
        if (getDynamicKeyOperation != null) {
            getDynamicKeyOperation.cancel();
        }
        if (uploadRoomInfoOperation != null) {
            uploadRoomInfoOperation.cancel();
        }
        waitRetry = false;
    }

    private void startCollector() {
        setState(STATE_STARTING);
        dynamicKey = null;
        getDynamicKeyOperation = CollectorApi.getDynamicKey(LocalSetting.getInstance().getRoomId(), new NetCallback<DynamicKey>() {
            @Override
            public void failed(NetOperation operation, NetError error) {
                if (error.isCanceled()) {
                    return;
                }
                CollectorStateManager.getInstance().setState(CollectorStateManager.STATE_RETRY_GET_CHANNEL_KEY, error.toString());
                onFailed();
            }

            @Override
            public void success(NetOperation operation, DynamicKey result) {
                if (!stopped) {
                    dynamicKey = result;
                    LogUtil.d("AGORA", "====uid:" + result.uid);
                    startAgora();
                }
                starting = false;
            }
        });
        startCountdown();
        waitRetry = false;
    }

    private void startAgora() {
        agoraManager = AgoraManager.start(
                dynamicKey.channelKey,
                LocalSetting.getInstance().getRoomId(),
                dynamicKey.uid,
                LocalSetting.getInstance().getVideoProfile(),
                new AgoraManager.Listener() {
                    @Override
                    public void onOpenCameraFailed() {
                        retry();
                        CollectorStateManager.getInstance().setState(CollectorStateManager.STATE_RETRY_CAMERA_ERROR, "开启摄像头失败");
                    }

                    @Override
                    public void onNewView(SurfaceView surfaceView) {

                    }

                    @Override
                    public void onDeleteView(SurfaceView surfaceView) {
                        if (CollectorManager.this.listener != null) {
                            CollectorManager.this.listener.onDeleteView(surfaceView);
                        }
                    }

                    @Override
                    public void onStartFailed() {
                        CollectorStateManager.getInstance().setState(CollectorStateManager.STATE_RETRY_SDK_LAUNCH, null);
                        onFailed();
                    }
                });
    }

    private void retry() {
        stopCollector();
        if (!stopped) {
            retryHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    startCollector();
                }
            }, RETRY_INTERVAL);
        }
        waitRetry = true;
    }

    private void onSuccess() {
        countdownHandler.removeCallbacksAndMessages(null);
        if (!stopped) {
            if (listener != null) {
                listener.onNewView(getSurfaceView());
            }
        }
    }

    private void onFailed() {
        retry();
    }

    private void setState(int state) {
        if (this.state == state) {
            return;
        }
        this.state = state;
        if (listener != null) {
            listener.onStateChanged(state);
        }
    }

    private void startCountdown() {
        countdownHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                CollectorStateManager.getInstance().setState(CollectorStateManager.STATE_RETRY_TIMEOUT, null);
                onFailed();
            }
        }, TIMEOUT);
    }

}
